'''
dionysus - a web based dialogue management framework
Copyright (C) 2011  Eugeniu Costetchi <eugeniu.costetchi (at) tudor.lu>

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

Created on Jan 12, 2011
'''
import collections
from DialogueManager.utils.utils import trim
from DialogueManager.utils.log_utils import log_debug

   
class Context(dict):
    CTX = '@ctx'
    DICTIONARY = 'dictionary'
    FORMAL_CODE = 'formal_code'
    QAF_TEMPLATES = 'qaf_templates'
    QAF_INSTANCES = 'qaf_instances'
    VARIABLES = 'variables'
    LAST_USER_UTTERANCE = 'last_user_utterance'
    NEXT_MACHINE_UTTERANCE = 'next_machine_utterance'
    ANALYSED_TYPE = 'analysed_type'
    ANALYSED_TOKENS = 'analysed_tokens'
    #TODO: move groups to protocol literals
    GROUPS = 'groups'
    
    __in = None
    __out = None
        
    #===========================================================================
    # construct the default 
    #===========================================================================
    def __init__(self):
        self[Context.DICTIONARY] = Dictionary()
        self[Context.FORMAL_CODE] = ''
        self[Context.QAF_TEMPLATES] = {} # aboutness: []
        self[Context.QAF_INSTANCES] = []  
        self[Context.VARIABLES] = {Context.GROUPS:{},}
        self[Context.VARIABLES]
        self[Context.LAST_USER_UTTERANCE] = {Context.ANALYSED_TYPE:None, Context.ANALYSED_TOKENS:None}
        self[Context.NEXT_MACHINE_UTTERANCE] = None
        self.__in = collections.deque()
        self.__out = collections.deque() 
        
        
    def set_emit(self, message):
        self.__out.append(message)
        #log_debug('S emit:' + str(self.__out))
    
    def get_emit(self):
        x = []
        while len(self.__out) > 0:
            x.append(self.__out.popleft())
        #log_debug('G emit:' + str(self.__out))
        return x
    
    def set_receive(self, message):
        self.__in.append(message)
        #log_debug('S receive:' + str(self.__in))
    
    def get_receive(self):
        x = []
        while len(self.__in) > 0:
            x.append(self.__in.popleft())
        #log_debug('G receive:' + str(self.__in))
        return ''.join(x)
    
    def __str__(self):
        ret = ''
        for i in self.keys():
            ret += '[' + i + ']=' + str(self.get(i)) + '\n'
        return ret
    
    def __repr__(self):
        return self.__str__()

class Dictionary(dict):
    
    AFFIRMATIVE = ['yes', 'y', 'ok', 'fine']
    NEGATIVE = ['no', 'n', 'nope', 'none']
    
    def __init__(self):
#        for i in Dictionary.AFFIRMATIVE:
#            self.add_words(i)
#        for i in Dictionary.NEGATIVE:
#            self.add_words(i)
        pass
    
    def get_words(self, prefix='' ,top=10):
        def fi(x): return x.startswith(prefix)
        return filter(fi,self.keys())[:top]
        
    def add_words(self, words):
        if isinstance(words, basestring):
            self.__add_word(words)
            return
        if isinstance(words, (list, set)):
            for i in words:
                self.add_words(i)
            
    def __add_word(self, w):
        if self.has_key(w):
            self[w] += 1
        else: self[w] = 1
        #this might be costly
        #sorted(self, key=self.get)

        
def access_context_object(operand, context):
    assert isinstance(operand, basestring)
    assert isinstance(context, Context)
    op = trim(operand.lower(), False)
    assert op.startswith(Context.CTX)
    path = op.split('.')
    del(path[0])
    x = context
    try:
        for i in path: x = x[i]
    except KeyError, TypeError:
        log_debug('Accessing context object by [' + operand + '] failed.', True)
        return None
    return x

def set_context_object(operand, value, context):
    assert isinstance(operand, basestring)
    assert isinstance(context, Context)
    op = trim(operand.lower(), False)
    assert op.startswith(Context.CTX)
    path = op.split('.')
    del(path[0])
    ref = path[-1]
    del(path[-1])
    x = context
    try:
        for i in path:
            if isinstance(x, dict):
                if x.has_key(i):
                    x = x[i]
                else: 
                    x[i] = dict()
                    x = x[i]
            else: 
                raise TypeError('trying to access non dictionary element')
        try:
            if isinstance(x[ref], dict) and isinstance(value, dict):
                x[ref].update(value)
            else:
                x[ref] = value
        except KeyError:
            x[ref] = value
    except KeyError, TypeError:
        log_debug('Accessing context object by [' + operand + '] failed.', True)
        return False
    return True    


#data = ["abba","babba","colly","querty","daddy","mommy","fully","hashy","belly","zakky","jully","quitty","kelly"]
#print data[:3]
#prefix='b'
#def fi(x): return x.startswith(prefix)
#q = filter(fi,data) 
#
#print q

#c = Context()
#print c
#set_context_object('@ctx.bubu.mama.ersfd.treyrty.dfgfhgd;cvb=``12\' ', True, c)
#print c